package com.tencent.qf.team.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tencent.qf.mybatis.pojo.PageRequest;
import com.tencent.qf.mybatis.pojo.PageResult;
import com.tencent.qf.team.dal.TySceneChannelRelation;
import com.tencent.qf.team.dal.TyShareCode;
import com.tencent.qf.team.dao.TyOrderDao;
import com.tencent.qf.team.dao.TySceneChannelRelationDao;
import com.tencent.qf.team.dao.TyShareCodeDao;
import com.tencent.qf.team.dto.db.GuiderShareGoodsOrderStatisticDo;
import com.tencent.qf.team.dto.db.GuiderShareGoodsOrderStatisticResDo;
import com.tencent.qf.team.dto.db.GuiderShareStatisticDo;
import com.tencent.qf.team.dto.db.GuiderShareStatisticReturnDo;
import com.tencent.qf.team.dto.request.GuiderShareStatisticRequest;
import com.tencent.qf.team.dto.response.GuiderSharePaginateResponse;
import com.tencent.qf.team.dto.response.GuiderShareStatisticResponse;
import com.tencent.qf.team.service.GuiderShareCpsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
public class GuiderShareCpsServiceImpl implements GuiderShareCpsService {

    @Autowired
    private TyShareCodeDao tyShareCodeDao;
    @Autowired
    private TySceneChannelRelationDao tySceneChannelRelationDao;
    @Autowired
    private TyOrderDao tyOrderDao;

    /**
     * 小B分享维度聚合数据
     *
     * @param request
     * @return
     */
    @Override
    public GuiderShareStatisticResponse guiderShareStatistic(GuiderShareStatisticRequest request) {
        List<LocalDateTime> dateList = this.splitDateTime(request.getStartDate(), request.getEndDate(), request.getDateType());
        if (CollectionUtils.isEmpty(dateList)) {
            return new GuiderShareStatisticResponse();
        }
        GuiderShareStatisticResponse response = new GuiderShareStatisticResponse();

        Integer shareCountTotal = 0;
        Integer goodsShareCountTotal = 0;
        Integer topicShareCountTotal = 0;
        Integer activityShareCountTotal = 0;
        Integer otherShareCountTotal = 0;
        Integer notesShareCountTotal = 0;
        Integer itemShareCountTotal = 0;

        for (LocalDateTime dateTime : dateList) {
            String startTime = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            String endTime;
            if (request.getDateType() == 1) {
                endTime = startTime.substring(0, 13) + ":59:59";
            } else {
                endTime = startTime.substring(0, 11) + "23:59:59";
            }
            GuiderShareStatisticDo shareStatisticDo = new GuiderShareStatisticDo();
            BeanUtils.copyProperties(request, shareStatisticDo);
            shareStatisticDo.setStartDate(startTime);
            shareStatisticDo.setEndDate(endTime);

            List<GuiderShareStatisticReturnDo> returnDos = tyShareCodeDao.guiderShareStatistic(shareStatisticDo);

            Integer shareCount = 0;
            Integer goodsShareCount = 0;
            Integer topicShareCount = 0;
            Integer activityShareCount = 0;
            Integer otherShareCount = 0;
            Integer notesShareCount = 0;
            Integer itemShareCount = 0;
            for (GuiderShareStatisticReturnDo returnDo : returnDos) {
                shareCountTotal += returnDo.getTypeShareCount();

                if ("goods".equals(returnDo.getShareContentType())) {
                    goodsShareCount += returnDo.getTypeShareCount();
                    shareCount += returnDo.getTypeShareCount();
                    goodsShareCountTotal += returnDo.getTypeShareCount();
                }
                if ("topic".equals(returnDo.getShareContentType())) {
                    topicShareCount += returnDo.getTypeShareCount();
                    shareCount += returnDo.getTypeShareCount();
                    topicShareCountTotal += returnDo.getTypeShareCount();
                }
                if ("activity".equals(returnDo.getShareContentType())) {
                    activityShareCount += returnDo.getTypeShareCount();
                    shareCount += returnDo.getTypeShareCount();
                    activityShareCountTotal += returnDo.getTypeShareCount();
                }
                if ("other".equals(returnDo.getShareContentType())) {
                    otherShareCount += returnDo.getTypeShareCount();
                    shareCount += returnDo.getTypeShareCount();
                    otherShareCountTotal += returnDo.getTypeShareCount();
                }
                if ("notes".equals(returnDo.getShareContentType())) {
                    notesShareCount += returnDo.getTypeShareCount();
                    shareCount += returnDo.getTypeShareCount();
                    notesShareCountTotal += returnDo.getTypeShareCount();
                }
                if ("item".equals(returnDo.getShareContentType())) {
                    itemShareCount += returnDo.getTypeShareCount();
                    shareCount += returnDo.getTypeShareCount();
                    itemShareCountTotal += returnDo.getTypeShareCount();
                }
            }

            response.getShareCountList().add(new GuiderShareStatisticResponse.CountList(startTime, shareCount, new String[]{startTime, endTime}));
            response.getGoodsShareCountList().add(new GuiderShareStatisticResponse.CountList(startTime, goodsShareCount, new String[]{startTime, endTime}));
            response.getTopicShareCountList().add(new GuiderShareStatisticResponse.CountList(startTime, topicShareCount, new String[]{startTime, endTime}));
            response.getActivityShareCountList().add(new GuiderShareStatisticResponse.CountList(startTime, activityShareCount, new String[]{startTime, endTime}));
            response.getOtherShareCountList().add(new GuiderShareStatisticResponse.CountList(startTime, otherShareCount, new String[]{startTime, endTime}));
            response.getNotesShareCountList().add(new GuiderShareStatisticResponse.CountList(startTime, notesShareCount, new String[]{startTime, endTime}));
            response.getItemShareCountList().add(new GuiderShareStatisticResponse.CountList(startTime, itemShareCount, new String[]{startTime, endTime}));
        }

        response.setTotalShareCount(shareCountTotal);
        response.setTotalGoodsShareCount(goodsShareCountTotal);
        response.setTotalTopicShareCount(topicShareCountTotal);
        response.setTotalActivityShareCount(activityShareCountTotal);
        response.setTotalOtherShareCount(otherShareCountTotal);
        response.setTotalNotesShareCount(notesShareCountTotal);
        response.setTotalItemShareCount(itemShareCountTotal);

        return response;
    }

    /**
     * 小B分享维度聚合分页-推广数据看板
     *
     * @param request
     * @return
     */
    @Override
    public PageResult<GuiderSharePaginateResponse> guiderSharePaginate(PageRequest<GuiderShareStatisticRequest> request) {
        GuiderShareStatisticRequest requestData = request.getData();

        if("v2".equals(requestData.getVersion())){
            return this.guiderSharePaginateV2(request);
        }

        // 排序字段，下划线转驼峰
        requestData.setOrderField(lineToHump(requestData.getOrderField()));
        GuiderShareStatisticDo shareStatisticDo = new GuiderShareStatisticDo();
        BeanUtils.copyProperties(requestData, shareStatisticDo);

        // 先查询出shareCode
        List<TyShareCode> shareCodes = tyShareCodeDao.queryShareCodes(shareStatisticDo);
        Set<String> shareCodeSet = null;
        if(!CollectionUtils.isEmpty(shareCodes)){
            shareCodeSet = new HashSet<>();
            for(TyShareCode tyShareCode : shareCodes){
                shareCodeSet.add(tyShareCode.getShareCode());
            }
            shareStatisticDo.setShareCodes(shareCodeSet);
        }

        // 成交渠道-处理
        Set<Integer> scenes = null;
        if(ArrayUtils.isNotEmpty(requestData.getDealChannel())){
            List<TySceneChannelRelation> list = tySceneChannelRelationDao.selectByChannelIds(requestData.getDealChannel());
            if(!CollectionUtils.isEmpty(list)) {
                scenes = new HashSet<>();
                for(TySceneChannelRelation data : list){
                    scenes.add(data.getScene());
                }
                shareStatisticDo.setScenes(scenes);
            }
        }

        PageHelper.startPage(request.getPageNo(), request.getPageSize());
        List<GuiderSharePaginateResponse> data = tyShareCodeDao.guiderSharePaginate(shareStatisticDo);
        PageInfo<GuiderSharePaginateResponse> pageInfo = new PageInfo(data);

        CountDownLatch latch = new CountDownLatch(data.size());
        for(GuiderSharePaginateResponse item : data){
            // 多线程，查该推广的交易统计
            new Thread(() ->{
                GuiderShareGoodsOrderStatisticDo orderStatisticDo = new GuiderShareGoodsOrderStatisticDo();
                BeanUtils.copyProperties(shareStatisticDo, orderStatisticDo);
                orderStatisticDo.setShareCodes(item.getShareCodes().split(","));
                orderStatisticDo.setShareCodeUid(item.getShareUid());
                if("goods".equals(requestData.getShareContentType())){
                    // 只有商品推广，才需要增加shareContentId和goodsId的匹配
                    orderStatisticDo.setShareContentId(item.getShareContentId());
                }
                if (StringUtils.isNotEmpty(shareStatisticDo.getStartDate())) {
                    long epochMilli = LocalDateTime.parse(shareStatisticDo.getStartDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toInstant(ZoneOffset.of("+8")).toEpochMilli();
                    orderStatisticDo.setStartDate(epochMilli);
                }
                if (StringUtils.isNotEmpty(shareStatisticDo.getEndDate())) {
                    long epochMilli = LocalDateTime.parse(shareStatisticDo.getEndDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toInstant(ZoneOffset.of("+8")).toEpochMilli();
                    orderStatisticDo.setEndDate(epochMilli);
                }
                GuiderShareGoodsOrderStatisticResDo orderStatisticResDo = tyOrderDao.guiderShareGoodsOrderStatistic(orderStatisticDo);
                if(orderStatisticResDo != null){
                    item.setBuyerCount(orderStatisticResDo.getBuyerCount());
                    item.setGmv(orderStatisticResDo.getGmv());
                    item.setPayGoodsSum(orderStatisticResDo.getPayGoodsSum());
                    item.setReturnedGoodsSum(orderStatisticResDo.getReturnedGoodsSum());
                }
                latch.countDown();
            }).start();
        }
        try {
            // 等待上面的查询线程全部执行完
            latch.await(6L, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.error("多线程查推广的交易统计，出现中断错误：", e);
            throw new RuntimeException("线程中断错误");
        }
        return PageResult.build(pageInfo);
    }

    /**
     * 小B分享维度聚合分页-推广数据看板
     *
     * @param request
     * @return
     */
    public PageResult<GuiderSharePaginateResponse> guiderSharePaginateV2(PageRequest<GuiderShareStatisticRequest> request) {

        GuiderShareStatisticRequest requestData = request.getData();
        // 排序字段，下划线转驼峰
        requestData.setOrderField(lineToHump(requestData.getOrderField()));
        GuiderShareStatisticDo shareStatisticDo = new GuiderShareStatisticDo();
        BeanUtils.copyProperties(requestData, shareStatisticDo);

        // 先查询出shareCode
        List<TyShareCode> shareCodes = tyShareCodeDao.queryShareCodes(shareStatisticDo);
        Set<String> shareCodeSet = null;
        if(!CollectionUtils.isEmpty(shareCodes)){
            shareCodeSet = new HashSet<>();
            for(TyShareCode tyShareCode : shareCodes){
                shareCodeSet.add(tyShareCode.getShareCode());
            }
            shareStatisticDo.setShareCodes(shareCodeSet);
        }

        // 成交渠道-处理
        Set<Integer> scenes = null;
        if(ArrayUtils.isNotEmpty(requestData.getDealChannel())){
            List<TySceneChannelRelation> list = tySceneChannelRelationDao.selectByChannelIds(requestData.getDealChannel());
            if(!CollectionUtils.isEmpty(list)) {
                scenes = new HashSet<>();
                for(TySceneChannelRelation data : list){
                    scenes.add(data.getScene());
                }
                shareStatisticDo.setScenes(scenes);
            }
        }

        PageHelper.startPage(request.getPageNo(), request.getPageSize());
        List<GuiderSharePaginateResponse> data = tyShareCodeDao.guiderSharePaginate(shareStatisticDo);
        PageInfo<GuiderSharePaginateResponse> pageInfo = new PageInfo(data);

        long currentTimeMillis = System.currentTimeMillis();
        log.info("推广数据看板-关联订单信息开始");
        CountDownLatch latch = new CountDownLatch(data.size());
        for(GuiderSharePaginateResponse item : data){
            // 多线程，查该推广的交易统计
            new Thread(() ->{
                try{
                    GuiderShareGoodsOrderStatisticDo orderStatisticDo = new GuiderShareGoodsOrderStatisticDo();
                    BeanUtils.copyProperties(shareStatisticDo, orderStatisticDo);
                    orderStatisticDo.setShareCodes(item.getShareCodes().split(","));
                    orderStatisticDo.setShareCodeUid(item.getShareUid());
                    orderStatisticDo.setSubBelongType(requestData.getSubBelongType());
                    if("goods".equals(requestData.getShareContentType())){
                        // 只有商品推广，才需要增加shareContentId和goodsId的匹配
                        orderStatisticDo.setShareContentId(item.getShareContentId());
                    }
                    if (StringUtils.isNotEmpty(shareStatisticDo.getStartDate())) {
                        long epochMilli = LocalDateTime.parse(shareStatisticDo.getStartDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toInstant(ZoneOffset.of("+8")).toEpochMilli();
                        orderStatisticDo.setStartDate(epochMilli);
                    }

                    GuiderShareGoodsOrderStatisticResDo orderStatisticResDo = tyOrderDao.guiderShareGoodsOrderStatisticV2(orderStatisticDo);
                    if(orderStatisticResDo != null){
                        BeanUtils.copyProperties(orderStatisticResDo, item);
                        // 件单价
                        if(item.getSuccGmv() != null && item.getSuccGmv() != 0 && item.getPayGoodsSum() != null && item.getPayGoodsSum() != 0){
                            item.setSuccPerPrice(new BigDecimal(item.getSuccGmv()).divide(new BigDecimal(item.getPayGoodsSum()), 2, RoundingMode.HALF_UP));
                        }
                    }
                }catch (Exception e){
                    log.error("推广数据看板-关联订单信息报错：", e);
                }finally {
                    latch.countDown();
                }
            }).start();
        }
        try {
            // 等待上面的查询线程全部执行完
            latch.await(4L, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.error("多线程查推广的交易统计，出现中断错误：", e);
            throw new RuntimeException("线程中断错误");
        }
        log.info("推广数据看板-关联订单信息结束 耗时：{}", System.currentTimeMillis() - currentTimeMillis);
        return PageResult.build(pageInfo);
    }

    /**
     * 下划线转驼峰
     */
    public static String lineToHump(String str) {
        Pattern linePattern = Pattern.compile("_(\\w)");
        str = str.toLowerCase();
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    private List<LocalDateTime> splitDateTime(String startDateStr, String endDateStr, Integer dateType) {
        if (StringUtils.isEmpty(startDateStr) || StringUtils.isEmpty(endDateStr)) {
            return null;
        }

        LocalDateTime startDate = LocalDateTime.parse(startDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        LocalDateTime endDate = LocalDateTime.parse(endDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        if (startDate.isAfter(endDate)) {
            return null;
        }

        List<LocalDateTime> result = new ArrayList<>();
        while (startDate.isBefore(endDate) || startDate.isEqual(endDate)) {
            result.add(startDate);
            if (dateType == 1) {
                startDate = startDate.plusHours(1);
            } else {
                startDate = startDate.plusDays(1);
            }
        }
        return result;
    }
}
